package main

import (
	"encoding/json"
	"errors"
	"fmt"
	copy2 "github.com/otiai10/copy"
	"golang.org/x/sys/windows"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"syscall"
)

type patcherData struct {
	Channel    string `json:"channel"`
	Type       string `json:"type"`
	Path       string `json:"path"`
	Mode       string `json:"mode"`
	PatchPatch string `json:"patch_path"`
}

var serverPort = ""

func main() {
	if len(os.Args) != 2 {
		panic("args Error")
	}
	serverPort = os.Args[1]
	if serverPort == "" {
		panic("port Error")
	}
	if !amAdmin() {
		runMeElevated()
		return
	}
	data := _getPatcherData(serverPort)
	fmt.Println(data)
	if data.Mode == "install" {
		/// 安装
		/// 先卸载之前的汉化文件，再写入
		_unInstallPatch(data)
		_installPatch(data)
	} else if data.Mode == "uninstall" {
		/// 卸载
		_unInstallPatch(data)
	}
}

func _installPatch(data *patcherData) {
	_sendResultMessageToBox("uninstalling")
	gamePath := data.Path
	cnTextPath := data.PatchPatch + "\\" + data.Type
	cnTextDataPath := cnTextPath + "\\data"
	cnTextCIGDLLPathPath := cnTextPath + "\\CIGDevelopmentTools.dll"
	cnTextConfFile := cnTextPath + "\\conf.json"
	gameDataPath := gamePath + "\\" + "data"
	gameBin64CIGDLLPath := gamePath + "\\" + "Bin64\\CIGDevelopmentTools.dll"
	gamePathConfFile := gamePath + "\\data\\conf.json"
	err := copy2.Copy(cnTextDataPath, gameDataPath)
	if err != nil {
		_sendErrorMessageToBox(err)
		return
	}
	err = copyFile(cnTextCIGDLLPathPath, gameBin64CIGDLLPath)
	if err != nil {
		_sendErrorMessageToBox(err)
		return
	}
	err = copyFile(cnTextConfFile, gamePathConfFile)
	if err != nil {
		_sendErrorMessageToBox(err)
		return
	}
	_sendResultMessageToBox("installed")
	fmt.Println("ok")
}

func _unInstallPatch(data *patcherData) {
	_sendResultMessageToBox("uninstalling")
	gamePath := data.Path
	gameDataPath := gamePath + "\\" + "data"
	gameBin64CIGDLLPath := gamePath + "\\" + "Bin64\\CIGDevelopmentTools.dll"
	gamePathConfFile := gamePath + "\\data\\conf.json"
	if _, err := os.Stat(gameBin64CIGDLLPath); err == nil {
		err := os.Remove(gameBin64CIGDLLPath)
		if err != nil {
			_sendErrorMessageToBox(err)
			panic(err)
		}
	}
	if _, err := os.Stat(gamePathConfFile); err == nil {
		err := os.Remove(gamePathConfFile)
		if err != nil {
			_sendErrorMessageToBox(err)
			panic(err)
		}
	}
	if _, err := os.Stat(gameDataPath); err == nil {
		err := os.RemoveAll(gameDataPath)
		if err != nil {
			_sendErrorMessageToBox(err)
			panic(err)
		}
	}
}

func _sendResultMessageToBox(setup string) {
	resp, err := http.Get("http://127.0.0.1:" + serverPort + "/" + setup)
	if err != nil {
		panic("GET_PATCHER_DATA_ERROR:" + err.Error())
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic("send Message Error")
	}
	bodyStr := string(body)
	if bodyStr != "ok" {
		panic("result error")
	}
}

func _sendErrorMessageToBox(err error) {
	resp, err := http.Post("http://127.0.0.1:"+serverPort+"/err",
		"text/plain", strings.NewReader(err.Error()))
	if err != nil {
		panic("GET_PATCHER_DATA_ERROR:" + err.Error())
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic("send ErrorMessage Error")
	}
	bodyStr := string(body)
	if bodyStr != "ok" {
		panic("result error")
	}
}

func _getPatcherData(port string) *patcherData {
	resp, err := http.Get("http://127.0.0.1:" + port + "/")
	if err != nil {
		panic("GET_PATCHER_DATA_ERROR:" + err.Error())
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic("GET_PATCHER_DATA_ERROR:" + err.Error())
	}
	var data patcherData
	err = json.Unmarshal(body, &data)
	if err != nil {
		panic("GET_PATCHER_DATA_ERROR:" + err.Error())
	}
	return &data
}

func copyFile(src string, dst string) error {
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer func() {
		_ = in.Close()
	}()

	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer func() {
		_ = out.Close()
	}()

	_, err = io.Copy(out, in)
	if err != nil {
		return err
	}
	return out.Close()
}

func runMeElevated() {
	verb := "runas"
	exe, _ := os.Executable()
	cwd, _ := os.Getwd()
	args := strings.Join(os.Args[1:], " ")

	verbPtr, _ := syscall.UTF16PtrFromString(verb)
	exePtr, _ := syscall.UTF16PtrFromString(exe)
	cwdPtr, _ := syscall.UTF16PtrFromString(cwd)
	argPtr, _ := syscall.UTF16PtrFromString(args)

	var showCmd int32 = 0 //SW_NORMAL

	err := windows.ShellExecute(0, verbPtr, exePtr, argPtr, cwdPtr, showCmd)
	if err != nil {
		fmt.Println(err)
		_sendErrorMessageToBox(errors.New("提权失败:" + err.Error()))
	}
}

func amAdmin() bool {
	_, err := os.Open("\\\\.\\PHYSICALDRIVE0")
	if err != nil {
		return false
	}
	return true
}
